package org.jeecg.modules.simulator.factory.person;

import lombok.Getter;
import lombok.Setter;
import org.jeecg.modules.simulator.jsonot.*;
import org.jeecg.modules.simulator.model.line.station.station.Station;
import org.jeecg.modules.simulator.model.line.station.station.TransferStation;
import org.jeecg.modules.simulator.model.person.Person;
import org.jeecg.modules.simulator.model.person.path.PersonPath;
import org.jeecg.modules.simulator.model.person.path.PersonPathItem;

import java.util.*;
import java.util.stream.Collectors;


public class PersonsCreater {

    @Getter
    @Setter
    Map<String, Station> stationMap;

    @Getter
    @Setter
    Map<String, TransferStation> transferStationMap;


    public List<Person> loadHistoryPersons(int size, Station station, Map<String, ODRouteNumRatio> ODRouteNumRatioMap) {


        List<Person> persons = new ArrayList<>();

        int odSize = ODRouteNumRatioMap.size();
        if (odSize >= size) {
            persons=odGreaterThanSize(size,  ODRouteNumRatioMap);
        } else {
            persons=ODLessThanSize(ODRouteNumRatioMap, odSize);
        }


        return persons;
    }

    //OD数小于即将进站的人--------需要修改
    /**
     * @description:
     * 算法：
     * 按OD均分给人然后根据占比分配路径
     *
     * @author:  renzhg 
     * @date:  2025/1/29 14:30
     **/
    private List<Person> ODLessThanSize(Map<String, ODRouteNumRatio> ODRouteNumRatioMap, int odSize) {
        List<Person> persons= new ArrayList<>();

        for (ODRouteNumRatio routeNumRatio : ODRouteNumRatioMap.values()) {
            List<ODProbabilityApiInfo> odProbabilityApiInfoList = routeNumRatio.getOdProbabilityApiInfoList();
            ODRoutes odRoutes = routeNumRatio.getOdRoutes();
            double totalPercentage = odProbabilityApiInfoList.stream()
                    .mapToDouble(info -> Double.parseDouble(info.getRouteRate()))
                    .sum();
            for (ODProbabilityApiInfo m : odProbabilityApiInfoList) {
                double percentage = Double.parseDouble(m.getRouteRate());
                // 根据百分比计算分配的金额
                long allocatedAmount = (long) ((odSize * percentage) / totalPercentage);
                String routeId = m.getRouteId();
                for (RoutePath routePath : odRoutes.getRoutePathList()) {
                    if (routeId.equals(routePath.getRouteName())) {
                        List<PressRouteStation> routeStations = routePath.getRoutes();

                        for (int i = 0; i < allocatedAmount; i++) {
                            Person person = createPersonPath(routeStations, routePath.getRouteName());
                            persons.add(person);
                        }


                    }
                }


            }
        }

        return persons;
    }

//OD数大于即将进站的人--即将进站的人

    /**
     * @description: 算法：
     * 因为OD数大于要进站的人数，在给进站的人分配OD时，无法均分，
     * 采用随机把od分给personsize的人数。
     * 然后采用OD中最大概率最大路径作为这个人的路径
     * @author: renzhg
     * @date: 2025/1/29 13:23
     **/
    public List<Person> odGreaterThanSize(int personSize, Map<String, ODRouteNumRatio> ODRouteNumRatioMap) {
//
        //分的OD数--一个路径对应一个人
        Map<String, ODRouteNumRatio> odRouteNumRatioMap = getRandomUniqueValues(personSize, ODRouteNumRatioMap);
        List<Person> persons = new ArrayList<>();


//        for (Map.Entry<String, ODRouteNumRatio> odRouteNumRatioEntry : odRouteNumRatioMap.entrySet())

        for(ODRouteNumRatio odRouteNumRatio:odRouteNumRatioMap.values()){


            List<ODProbabilityApiInfo> odProbabilityApiInfoList = odRouteNumRatio.getOdProbabilityApiInfoList();
            //获取这个OD最大的概率
            Optional<ODProbabilityApiInfo> maxRouteRateInfo = odProbabilityApiInfoList.stream()
                    .max(Comparator.naturalOrder());
            List<RoutePath> routePathList = odRouteNumRatio.getOdRoutes().getRoutePathList();


            ODProbabilityApiInfo odProbabilityApiInfo = maxRouteRateInfo.get();//最大概率的路径信息


            for (RoutePath routePath : routePathList) {
                //当路径ID相等的时候获取路径
                if (routePath.getRouteName().equals(odProbabilityApiInfo.getRouteId())) {
                    List<PressRouteStation> routeStations = routePath.getRoutes();
                    Person person = createPersonPath(routeStations, routePath.getRouteName());
                    persons.add(person);
                }
            }


        }
        return  persons;
    }

    /**
     * 从给定的 ODRouteNumRatioMap 中随机选择指定数量的唯一键值对。
     * 因为OD个数大于即将进站的人，无法平均给人分配OD,
     * 所以，采用随机的方式产生了一堆OD
     *
     * @param personSize         将要进站的人数
     * @param ODRouteNumRatioMap 包含所有可供选择的键值对的映射
     * @return 一堆数据的od
     */

    public Map<String, ODRouteNumRatio> getRandomUniqueValues(int personSize, Map<String, ODRouteNumRatio> ODRouteNumRatioMap) {
        //随机给出一个不重复的od
        List<String> keys = new ArrayList<>(ODRouteNumRatioMap.keySet());//OD个数
        // 随机打乱List
        Collections.shuffle(keys);
        // 创建一个新的映射以存储随机选择的键值对
        Map<String, ODRouteNumRatio> result = new HashMap<>();
        for (int i = 0; i < personSize; i++) {
            String key = keys.get(i);
            // 将键及其对应的值添加到结果映射中
            result.put(key, ODRouteNumRatioMap.get(key));
        }
        // 返回前numberOfValues个值
        return result;


    }


    private Person addPersonForRoute(String routeId, List<PersonPathItem> personPathItemList) {
        PersonPath personPath = new PersonPath(personPathItemList);
        Person person = new Person(personPath);
        person.setId(UUID.randomUUID().toString());
        person.setInStationState();
        return person;
    }


    private Person createPersonPath(List<PressRouteStation> routeStations, String routeId) {
        List<PersonPathItem> personPathItems = generatePersonPathItemList(routeStations, routeId);

        Person person = addPersonForRoute(routeId, personPathItems);
        return person;

    }

    private List<PersonPathItem> generatePersonPathItemList(List<PressRouteStation> routeStations, String routeId) {
        List<PersonPathItem> personPathItems = new ArrayList<>();
        for (int n = 0; n < routeStations.size(); n++) {
            PersonPathItem personPathItem = new PersonPathItem();
            String stationId = routeStations.get(n).getStationId();

            Station station = stationMap.get(stationId);
            if (station == null) {
                return null;
            }


            personPathItem.setStationId(stationId);
            String name = stationMap.get(stationId).getName();
            personPathItem.setStationName(name);
            personPathItem.setIndex(n);
            transferStationMap.forEach((k, v) -> {
                if (isInTransferStation(name)) {
                    personPathItem.setTransfer(true);
                } else {
                    personPathItem.setNeedTransfer(false);
                }
            });
            if (routeStations.get(n).getTripDrctCd() == null) {
                routeStations.get(n).setTripDrctCd("");
            }
            if (routeStations.get(n).getTripDrctCd().isEmpty()) {
                personPathItem.setNeedTransfer(true);
            } else {
                personPathItem.setNeedTransfer(false);
            }
            personPathItem.setPathIndex(routeId);
            personPathItems.add(personPathItem);
        }
        return personPathItems;
    }

    public Boolean isInTransferStation(String name) {

        return transferStationMap.values().stream()
                .anyMatch(value -> value.getName().equals(name));

    }



}
